
package GeneticAlgorithm;

import Individual.*;
import Loader.*;
import Settings.*;

public class GeneticAlgorithm {

    private Individual[] individuals;
    private int generation;  
    private BufferedData bufferedData;
    private FitnessFunctions fitnessFunctions;
    private StatisticFunctions statisticFunctions;

    public GeneticAlgorithm() {

        Loader loader = new Loader();
        bufferedData = loader.load(Settings.FILE);       
        individuals = new Individual[Settings.POPULATION];
        fitnessFunctions = new FitnessFunctions(bufferedData);
        statisticFunctions = new StatisticFunctions( individuals,
                                                     fitnessFunctions,
                                                     bufferedData
                                                   );

    }

    public void run() {

        if(bufferedData.data == null) {

            System.out.println("Brak danych!");
            return;

        }

        System.out.println(String.format( "Probability mutation: %2.12f",
                                          Settings.PROPABILITY_MUTATION)
                                        );

        int shuffleIteration = 0;
        int repeatGeneration = 0;
        Individual bestIndividual = null;
        double fitBestIndividual = 0;

        /*
        //standard deviation
        float[] avgFitsL = new float[ Settings.SHUFFLE_PER_ITERATION *
                                      Settings.REPEAT_GENERATION_PER_ITERATION
                                     ];
        float[] avgFitsT = new float[ Settings.SHUFFLE_PER_ITERATION *
                                      Settings.REPEAT_GENERATION_PER_ITERATION
                                     ];
        float[] bestFitsL = new float[ Settings.SHUFFLE_PER_ITERATION *
                                       Settings.REPEAT_GENERATION_PER_ITERATION
                                     ];
        float[] bestFitsT = new float[ Settings.SHUFFLE_PER_ITERATION *
                                       Settings.REPEAT_GENERATION_PER_ITERATION
                                     ];
        int countResearch = 0;
        float meanAvgL = 0;
        float meanAvgT = 0;
        float meanBestL = 0;
        float meanBestT = 0;
        float stDevAvgL = 0;
        float stDevAvgT = 0;
        float stDevBestL = 0;
        float stDevBestT = 0;
        */

        int iterationCounter = 0;

        while(shuffleIteration < Settings.SHUFFLE_PER_ITERATION) {

            bufferedData.shuffleData(Settings.NUMBER_OF_REPEAT_SHUFFLE_DATA);
            repeatGeneration = 0;
            while(repeatGeneration < Settings.REPEAT_GENERATION_PER_ITERATION) {

                Initialization.initialization(individuals, bufferedData);
                generation = 0;
                while(generation < Settings.GENERATION) {

                    ReproductionFunctions.reproduction( fitnessFunctions,
                                                        individuals,
                                                        bufferedData
                                                      );

                    CrossoverFunctions.crossover( individuals );

                    MutationFunctions.mutation( individuals );

                    if(Settings.PRINT_DEBBUG) {

                        if(generation % 9 == 0) {
                            float bFit = statisticFunctions.bestFitness(true);
                            String bestFitL = String.format(
                                                "Best Fit in %d gener.:%2.7f",
                                                generation,
                                                bFit
                                               );
                            System.out.println(bestFitL);
                        }

                    }

                    generation++;
                }

                
                float avgFitLVal = statisticFunctions.averageFitness(true);
                float avgFitTVal = statisticFunctions.averageFitness(false);
                float bestFitLVal = statisticFunctions.bestFitness(true);
                float bestFitTVal = statisticFunctions.bestFitness(false);
                String avgFitL = String.format( "AVG Fit for learn data: %2.7f",
                                                avgFitLVal
                                              );
                String avgFitT = String.format( "AVG Fit for test data: %2.7f",
                                                avgFitTVal
                                              );
                String bestFitL = String.format("Best Fit for learn data:%2.7f",
                                                bestFitLVal
                                               );
                String bestFitT = String.format("Best Fit for test data: %2.7f",
                                                bestFitTVal
                                               );
                System.out.println(avgFitL);
                System.out.println(avgFitT);
                System.out.println(bestFitL);
                System.out.println(bestFitT);

                //statisticFunctions.printCentroidsBestIndividual();
                statisticFunctions.printCountersAssigned(true);
                statisticFunctions.printCountersAssigned(false);

                /*
                //standard deviation
                avgFitsL[countResearch] = avgFitLVal;
                avgFitsT[countResearch] = avgFitTVal;
                bestFitsL[countResearch] = bestFitLVal;
                bestFitsT[countResearch] = bestFitTVal;
                countResearch++;

                System.out.println("Iteration "+countResearch+" finished");
                */

                Individual tempBestInd = statisticFunctions.getBestIndividual().individual;
                if(fitBestIndividual < bestFitLVal) {
                    fitBestIndividual = bestFitLVal;
                    bestIndividual = tempBestInd;
                }
                System.out.println("-----------------------------------------");
                System.out.println("Measures for learn data (Beta=0.5):");
                statisticFunctions.printPrecisionRecall(true, 0.5, tempBestInd);
                System.out.println("Measures for test data (Beta=0.5):");
                statisticFunctions.printPrecisionRecall(false, 0.5,tempBestInd);

                iterationCounter++;
                System.out.println("Iteration: "+iterationCounter);
                
                repeatGeneration++;

            }

            shuffleIteration++;
        }

        System.out.println("Measures for learn data best individ.(Beta=0.5):");
        statisticFunctions.printPrecisionRecall(true, 0.5, bestIndividual);
        System.out.println("Measures for test data best individ.(Beta=0.5):");
        statisticFunctions.printPrecisionRecall(false, 0.5, bestIndividual);

        try {
        statisticFunctions.paintRecordsAndCentres(bestIndividual, "plik");
        } catch(Exception e) {
        }
        /*
        //standard deviation
        for(int i = 0; i < countResearch; ++i) {
            meanAvgL += avgFitsL[i];
            meanAvgT += avgFitsT[i];
            meanBestL += bestFitsL[i];
            meanBestT += bestFitsT[i];
        }
        meanAvgL /= countResearch;
        meanAvgT /= countResearch;
        meanBestL /= countResearch;
        meanBestT /= countResearch;
        for(int i = 0; i < countResearch; ++i) {
            stDevAvgL += Math.pow( (avgFitsL[i] - meanAvgL), 2);
            stDevAvgT += Math.pow( (avgFitsT[i] - meanAvgT), 2);
            stDevBestL += Math.pow( (bestFitsL[i] - meanBestL), 2);
            stDevBestT += Math.pow( (bestFitsT[i] - meanBestT), 2);
        }
        stDevAvgL /= countResearch - 1;
        stDevAvgT /= countResearch - 1;
        stDevBestL /= countResearch - 1;
        stDevBestT /= countResearch - 1;

        System.out.println("Standard deviation:");
        System.out.println(String.format("For AVG learn data: %2.7f",
                                         Math.sqrt(stDevAvgL)));
        System.out.println(String.format("For AVG test data: %2.7f",
                                         stDevAvgT));
        System.out.println(String.format("For BEST learn data: %2.7f",
                                         stDevBestL));
        System.out.println(String.format("For BEST test data: %2.7f",
                                         stDevBestT));
        */

    }

}
